package cn.darkhorse.alarm.service.impl;

import cn.darkhorse.alarm.pojo.AlarmParameterSettings;
import cn.darkhorse.alarm.pojo.AlarmRecordInfo;
import cn.darkhorse.alarm.pojo.AlarmRecordTime;
import cn.darkhorse.alarm.pojo.AlarmRecordUserInfo;
import cn.darkhorse.alarm.service.AlarmHandlerService;
import cn.darkhorse.alarm.service.AlarmRecordInfoService;
import cn.darkhorse.alarm.service.AlarmRecordTimeService;
import cn.darkhorse.alarm.service.AlarmRecordUserInfoService;
import cn.darkhorse.alarm.service.alarm.BaseAlarm;
import cn.darkhorse.common.constant.CommonConstant;
import cn.darkhorse.common.util.DateUtilOther;
import cn.darkhorse.common.util.RedisUtil;
import cn.darkhorse.device.iot.constant.IotConstant;
import cn.darkhorse.device.pojo.MesDevice;
import cn.darkhorse.device.service.IotInstructParamsService;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 报警处理实现类
 */
@Service
public class AlarmHandlerImpl implements AlarmHandlerService {
    @Resource
    private AlarmRecordInfoService alarmRecordInfoService;
    @Resource
    private AlarmRecordUserInfoService alarmRecordUserInfoService;
    @Resource
    private AlarmRecordTimeService alarmRecordTimeService;

    @Autowired
    private IotInstructParamsService instructParamsService;
    @Autowired
    private RedisCache redisCache;
    /**
     * 处理实时报警
     *
     * @param json
     * @param sysUserMap
     * @param settingsMap
     * @param deviceMap
     * @param recordSwitchMap
     * @param recordValueLimitMap
     * @param recordValueImmediateMap
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doHandler(String json, Map<Long, SysUser> sysUserMap, Map<Long, AlarmParameterSettings> settingsMap,
                          Map<Long, MesDevice> deviceMap, Map<String, AlarmRecordInfo> recordSwitchMap,
                          Map<String, AlarmRecordInfo> recordValueLimitMap, Map<String, AlarmRecordInfo> recordValueImmediateMap,
                          Map<String, String> paramsDescription) {
        JSONObject jsonObject = JSONObject.parseObject(json);
        Long settingsId = jsonObject.getLongValue("settingsId");
        String value = jsonObject.getString("value");
        Date time = jsonObject.getDate("time");
        //参数设置
        if (!settingsMap.containsKey(settingsId)) {
            return;
        }
        AlarmParameterSettings settings = settingsMap.get(settingsId);
        if(null == settings.getAlarm() || !settings.getAlarm()){
            return;
        }
        if (!deviceMap.containsKey(settings.getDeviceId())) {
                return;
        }
        MesDevice device = deviceMap.get(settings.getDeviceId());


        LocalDateTime localDateTime = DateUtilOther.parseLocalDatetime(time);
        String alarmNotifier = null;
//        TODO 报警接收人
//        MesCompany mesCompany = companyService.getById(device.getCompany());
//        if (mesCompany!=null){
//            Long mainUserId = mesCompany.getMainUserId();
//            if (mainUserId != null)        {
//                alarmNotifier = mainUserId.toString();
//            }else {
//                alarmNotifier = "1";
//            }
//        }else {
//            alarmNotifier = "1";
//        }


        if (StringUtils.isNotBlank(alarmNotifier)) {
            AlarmRecordInfo recordInfo = new AlarmRecordInfo();
            recordInfo.setAlarmDate(localDateTime);
            recordInfo.setCreateTime(LocalDateTime.now());
            recordInfo.setAlarmValue(value);
            recordInfo.setDeviceId(device.getId());
            recordInfo.setParameterId(settings.getId());
            recordInfo.setAlarmNotifier(alarmNotifier);
            recordInfo.setParameterType(settings.getParameterType());
            recordInfo.setAlarmType(settings.getAlarmType());
            recordInfo.setAlarmStatus(0);
            checkAlarm(settings, recordInfo, value,paramsDescription);
            //实时报警
            if (CommonConstant.ALARM_FREQUENCY_IMMEDIATE == settings.getAlarmFrequency()) {
                recordInfo.setAlarmFrequency(CommonConstant.ALARM_FREQUENCY_IMMEDIATE);
                List<AlarmRecordUserInfo> alarmRecordUserInfos = getAlarmUser(alarmNotifier, sysUserMap, recordInfo);
                if (settings.getSendToGateway() == 1){
                    if (settings.getInstructId()!=null){
                        instructParamsService.doPush(settings.getInstructId());
                    }
                }
                alarmRecordInfoService.save(recordInfo);
                alarmRecordUserInfos.forEach(item -> {
                    item.setRecordId(recordInfo.getId());
                });
                alarmRecordUserInfoService.saveBatch(alarmRecordUserInfos);
                //报警次数统计表
                long count=alarmRecordTimeService.getCount(recordInfo);
                if(count==0){
                    AlarmRecordTime recordTime=new AlarmRecordTime();
                    BeanUtils.copyProperties(recordInfo,recordTime,new String[]{"id"});
                    recordTime.setAlarmRecordId(recordInfo.getId());
                    alarmRecordTimeService.save(recordTime);
                }

                redisCache.setCacheObject(IotConstant.CACHE_MQTT_LIVE_ALARM_DATA+recordInfo.getDeviceId(),recordInfo);
                //删除缓存
                RedisUtil.setRemove(CommonConstant.ALARM_LIST, json);
            }
            //间隔报警
            if (CommonConstant.ALARM_FREQUENCY_INTERVAL == settings.getAlarmFrequency()) {
                recordInfo.setAlarmFrequency(CommonConstant.ALARM_FREQUENCY_INTERVAL);
                if(checkInterVal(settings,recordInfo,value,recordSwitchMap,recordValueLimitMap,recordValueImmediateMap)){
                    List<AlarmRecordUserInfo> alarmRecordUserInfos = getAlarmUser(alarmNotifier, sysUserMap, recordInfo);
                    alarmRecordInfoService.save(recordInfo);
                    if (settings.getSendToGateway() == 1){
                        if (settings.getInstructId()!=null){
                            instructParamsService.doPush(settings.getInstructId());
                        }
                    }
                    alarmRecordUserInfos.forEach(item -> {
                        item.setRecordId(recordInfo.getId());
                    });
                    alarmRecordUserInfoService.saveBatch(alarmRecordUserInfos);
                    //报警次数统计表
                    long count=alarmRecordTimeService.getCount(recordInfo);
                    if(count==0){
                        AlarmRecordTime recordTime=new AlarmRecordTime();
                        BeanUtils.copyProperties(recordInfo,recordTime,new String[]{"id"});
                        recordTime.setAlarmRecordId(recordInfo.getId());
                        alarmRecordTimeService.save(recordTime);
                    }
                }
                redisCache.setCacheObject(IotConstant.CACHE_MQTT_LIVE_ALARM_DATA+recordInfo.getDeviceId(),recordInfo);
                //删除缓存
                RedisUtil.setRemove(CommonConstant.ALARM_LIST, json);
            }
        }
    }


    /**
     * 是否需要报警
     * @param settings
     * @param recordInfo
     * @param value
     * @param recordOtherMap
     * @param recordValueLimitMap
     * @param recordValueImmediateMap
     * @return
     */
    public boolean checkInterVal(AlarmParameterSettings settings,AlarmRecordInfo recordInfo,String value,
                              Map<String, AlarmRecordInfo> recordOtherMap, Map<String, AlarmRecordInfo> recordValueLimitMap,
                              Map<String, AlarmRecordInfo> recordValueImmediateMap){
        String key=recordInfo.getDeviceId()+":"+recordInfo.getParameterId()+":"+recordInfo.getParameterType();
        AlarmRecordInfo info =null;
        if(BaseAlarm.ALARM_OTHER.equals(recordInfo.getAlarmType())){
            key = key+":"+value;
            if(recordOtherMap.containsKey(key)){
                info=recordOtherMap.get(key);
                long mills = DateUtilOther.toMinus(info.getAlarmDate(), recordInfo.getAlarmDate());
                //间隔时间内不报警
                if(settings.getIntervalTime()*1000>=mills){
                    info.setAlarmDate(recordInfo.getAlarmDate());
                    recordOtherMap.put(key,info);
                    return false;
                }
            }
        }
        //限值
        if(BaseAlarm.ALARM_LIMIT_VALUE.equals(recordInfo.getAlarmType())){
             key=key+":"+recordInfo.getLimitType();
            if(recordValueLimitMap.containsKey(key)){
                info=recordValueLimitMap.get(key);
                long mills = DateUtilOther.toMinus(info.getAlarmDate(), recordInfo.getAlarmDate());
                //间隔时间内不报警
                if(settings.getIntervalTime()*1000>=mills){
                    return false;
                }else{
                    info.setAlarmDate(recordInfo.getAlarmDate());
                    recordValueLimitMap.put(key,info);
                }
            }
        }
        //连续
        if(BaseAlarm.ALARM_CONTINUOUS_VALUE.equals(recordInfo.getAlarmType())){
             key=key+":"+recordInfo.getImmediatelyValue();
            if(recordValueImmediateMap.containsKey(key)){
                info=recordValueImmediateMap.get(key);
                long mills = DateUtilOther.toMinus(info.getAlarmDate(), recordInfo.getAlarmDate());
                //间隔时间内不报警
                if(settings.getIntervalTime()*1000>=mills){
                    info.setAlarmDate(recordInfo.getAlarmDate());
                    recordValueImmediateMap.put(key,info);
                    return false;
                }
            }
        }
        return  true;
    }

    /**
     * 校验报警类型
     * @param settings
     * @param recordInfo
     * @param value
     */
    public void checkAlarm(AlarmParameterSettings settings,AlarmRecordInfo recordInfo,String value,Map<String, String> paramsDescription){
        String msg="";
        String alarmParamsName = "";
        String limitValue="--";
        JSONArray jsonArray = JSONArray.parseArray(settings.getAlarmMessage());
        //暂定    布尔型、枚举、字段
        if(!settings.getParameterType().equals(BaseAlarm.ALARM_PARAMETER_TYPE_NUMERICAL)){
            for (Object o : jsonArray) {
                JSONObject jsonObject=JSONObject.parse(o.toString());
                //double alarmValue=jsonObject.getDoubleValue("value");
                String alarmValue=jsonObject.getString("value");
                if(value.equals(alarmValue)){
                    msg=jsonObject.getString("msg");
                    String paramsName = paramsDescription.get(settings.getPointTableId() + ":" + alarmValue);
                    alarmParamsName = StringUtils.isBlank(paramsName)?value:paramsName;
                }
            }
        }
        if(settings.getParameterType().equals(BaseAlarm.ALARM_PARAMETER_TYPE_NUMERICAL)){
            //限值报警
            if(BaseAlarm.ALARM_LIMIT_VALUE.equals(settings.getAlarmType())){
                JSONObject jsonObject0 = jsonArray.getJSONObject(0);
                JSONObject jsonObject1 = jsonArray.getJSONObject(1);
                double maxValue=0;
                String maxMsg="";
                double minValue=0;
                String minMsg="";
                if(jsonObject0.containsKey("maxValue")){
                    maxValue=jsonObject0.getDoubleValue("maxValue");
                    maxMsg=jsonObject0.getString("msg");
                    minValue=jsonObject1.getDoubleValue("minValue");
                    minMsg=jsonObject1.getString("msg");
                }else{
                    maxValue=jsonObject1.getDoubleValue("maxValue");
                    maxMsg=jsonObject1.getString("msg");
                    minValue=jsonObject0.getDoubleValue("minValue");
                    minMsg=jsonObject0.getString("msg");
                }
                if(Double.valueOf(value)>maxValue){
                    msg=maxMsg;
                    recordInfo.setLimitType(CommonConstant.ALARM_LIMIT_TYPE_MORE);
                }
                if(Double.valueOf(value)<minValue){
                    msg=minMsg;
                    recordInfo.setLimitType(CommonConstant.ALARM_LIMIT_TYPE_LESS);
                }
                limitValue=minValue+"~"+maxValue;
               // alarmParamsName = "限值报警";
                alarmParamsName = limitValue;
            }
            //连续报警
            if(BaseAlarm.ALARM_CONTINUOUS_VALUE.equals(settings.getAlarmType())){
                for (Object o : jsonArray) {
                    JSONObject jsonObject=JSONObject.parse(o.toString());
                    //double alarmValue=jsonObject.getDoubleValue("value");
                    String alarmValue=jsonObject.getString("value");
                    if(value.equals(alarmValue)){
                        msg=jsonObject.getString("msg");
                        BigDecimal bd = new BigDecimal(alarmValue);
                        recordInfo.setImmediatelyValue(bd.setScale(2, BigDecimal.ROUND_HALF_UP));
                        limitValue=String.valueOf(alarmValue);
                        //alarmParamsName = "连续报警";
                        alarmParamsName = limitValue;
                    }
                }
            }
        }
        recordInfo.setAlarmMessage(msg);
        recordInfo.setLimitValue(limitValue);
        recordInfo.setAlarmParamsName(alarmParamsName);
    }
    /**
     * 更新报警记录用户关联表
     * @param alarmNotifier
     * @param sysUserMap
     * @param recordInfo
     */
    public List<AlarmRecordUserInfo> getAlarmUser(String  alarmNotifier, Map<Long, SysUser> sysUserMap, AlarmRecordInfo recordInfo){
        String[] notifiers=alarmNotifier.split(",");
        List<AlarmRecordUserInfo> alarmRecordUserInfos=new ArrayList<>();
        String alarmNotifierName="";
        for (String notifier : notifiers) {
            if(sysUserMap.containsKey(Long.valueOf(notifier))){
                AlarmRecordUserInfo userInfo=new AlarmRecordUserInfo();
                userInfo.setUserId(Long.valueOf(notifier));
                userInfo.setRecordId(recordInfo.getId());
                alarmRecordUserInfos.add(userInfo);
                alarmNotifierName+=sysUserMap.get(Long.valueOf(notifier)).getNickName()+",";
            }
        }
        if(StringUtils.isNotBlank(alarmNotifierName)){
            alarmNotifierName=alarmNotifierName.substring(0,alarmNotifierName.length()-1);
            recordInfo.setAlarmNotifierName(alarmNotifierName);
        }
        return alarmRecordUserInfos;
    }








}
